﻿using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NPOI.XSSF.UserModel;
using StarsAdmin.Core.DB.Entities;
using StarsAdmin.Core.Exceptions;
using StarsAdmin.Core.Helpers;
using System.IO.Compression;

namespace StarsAdmin.Core.Extensions
{
    public static class FileExtension
    {
        // 自定义文件类型映射
        private static readonly Dictionary<string, string> customMappings = new Dictionary<string, string>()
        {
            { ".dwg", "application/acad" },
            { ".rvt", "application/vnd.rvt" },
            { ".rfa", "application/vnd.rfa" },
            { ".rte", "application/vnd.rte" },
            { ".skp", "application/vnd.skp" },
            { ".max", "application/vnd.max" },
            { ".3ds", "application/vnd.3ds" },
            { ".gltf", "application/vnd.gltf" },
            { ".gld", "application/vnd.gld" },
            { ".obj", "application/vnd.obj" },
            { ".fbx", "application/vnd.fbx" },
            { ".ifc", "application/vnd.ifc" }
        };

        public static FileStreamResult GetZipFileStreamResult(this List<FileEntity> files, string webRootPath, string zipName = "files")
        {
            // 创建临时ZIP文件
            string zipPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".zip");

            using (var zipArchive = ZipFile.Open(zipPath, ZipArchiveMode.Create))
            {
                foreach (var file in files)
                {
                    var filePath = webRootPath.CombineAndFormatPath(file.FileDirectory);
                    if (File.Exists(filePath))
                    {
                        zipArchive.CreateEntryFromFile(filePath, file.FileName + file.Extension);
                    }
                }
            }
            // 返回ZIP文件流
            var fileStream = new FileStream(zipPath, FileMode.Open);
            return new FileStreamResult(fileStream, "application/zip")
            {
                FileDownloadName = zipName + ".zip",
            };
        }

        public static FileStreamResult GetFileStreamResult(this string fileDirectory, string webRootPath, string fileExtension, string fileName = "file")
        {
            var filePath = webRootPath.CombineAndFormatPath(fileDirectory);
            var fileStream = new FileStream(filePath, FileMode.Open);
            return new FileStreamResult(fileStream, fileExtension.GetFileContentType())
            {
                FileDownloadName = fileName + fileExtension,
            };
        }

        public static async Task<FileContentResult> ToExcelAsync<T>(this IEnumerable<T> source, string fileName = "导出默认模版", string sheetName = "Sheet1")
        {
            return await Task.FromResult(source.ToExcel(fileName, sheetName));
        }

        public static FileContentResult ToExcel<T>(this IEnumerable<T> source, string fileName = "导出默认模版", string sheetName = "Sheet1")
        {
            if (source == null || source.Count() == 0)
            {
                throw new ArgumentNullException(nameof(source));
            }
            // 创建Excel文件的对象
            var workbook = new XSSFWorkbook();
            // 添加一个新的工作表
            var sheet = workbook.CreateSheet(sheetName);
            // 添加第一行的头部标题
            var headerRow = sheet.CreateRow(0);
            headerRow.Height = 30 * 20;
            // 设置样式
            var headerStyle = workbook.GetHeaderStyle();
            var commonCellStyle = workbook.GetCommonStyle();

            // 获取数据的类型信息
            var properties = typeof(T).GetProperties();
            // 写入表头
            var index = headerRow.CreateCell(0);
            index.SetCellValue("序号");
            index.CellStyle = headerStyle;
            for (int i = 0; i < properties.Length; i++)
            {
                var cell = headerRow.CreateCell(i + 1);
                cell.SetCellValue(properties[i].Name);
                cell.CellStyle = headerStyle;
            }

            // 写入数据行
            int rowIndex = 1;
            foreach (var item in source)
            {
                var row = sheet.CreateRow(rowIndex++);

                var indexCell = row.CreateCell(0);
                indexCell.SetCellValue(rowIndex - 1);
                indexCell.CellStyle = commonCellStyle;

                for (int i = 0; i < properties.Length; i++)
                {
                    var cell = row.CreateCell(i + 1);

                    var value = properties[i].GetValue(item);

                    // 根据值的类型设置单元格内容
                    if (value != null)
                    {
                        if (value is DateTime dateTimeValue)
                        {
                            cell.SetCellValue(dateTimeValue.ToString());
                        } else if (value is Enum enumValue)
                        {
                            cell.SetCellValue(enumValue.GetDescription());
                        } else if (value is bool boolValue)
                        {
                            cell.SetCellValue(boolValue ? "是" : "否");
                        } else if (value is double numericValue)
                        {
                            cell.SetCellValue(numericValue);
                        } else if (value is string stringValue)
                        {
                            cell.SetCellValue(stringValue);
                        } else
                        {
                            cell.SetCellValue(value.ToString());
                        }
                    }

                    cell.CellStyle = commonCellStyle;
                }
            }
            // 自动调整所有列的宽度以适应内容
            for (int i = 0; i < properties.Length + 1; i++)
            {
                sheet.AutoSizeColumn(i);
            }
            // 写入到excel
            using var ms = new MemoryStream();
            workbook.Write(ms);
            var extension = ".xlsx";
            return new FileContentResult(ms.ToArray(), extension.GetFileContentType()) { FileDownloadName = $"{fileName}.xlsx" };
        }

        public static async Task<FileContentResult> ExportExcelFileAsync(string localPath)
        {
            return await Task.FromResult(ExportExcelFile(localPath));
        }

        public static FileContentResult ExportExcelFile(string localPath)
        {
            var memory = new MemoryStream();
            using (var stream = new FileStream(localPath, FileMode.Open))
            {
                stream.CopyTo(memory);
            }
            memory.Position = 0;
            var extension = ".xlsx";
            return new FileContentResult(memory.ToArray(), extension.GetFileContentType()) { FileDownloadName = "用户管理.xlsx" };
        }

        /// <summary>
        /// 保存文件
        /// </summary>
        /// <param name="file"></param>
        /// <param name="filePath"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static async Task SaveAsync(this IFormFile file, string filePath, CancellationToken cancellationToken = default)
        {
            using var stream = File.Create(filePath);
            await file.CopyToAsync(stream, cancellationToken);
        }

        /// <summary>
        /// 复制文件夹及文件
        /// </summary>
        /// <param name="sourceFolder">原文件路径</param>
        /// <param name="destFolder">目标文件路径</param>
        /// <returns></returns>
        public static bool CopyFolder(this string sourceFolder, string destFolder, List<string> excludes = null)
        {
            try
            {
                //int num = 0;
                //得到原文件根目录下的所有文件
                string[] files = System.IO.Directory.GetFiles(sourceFolder);
                foreach (string file in files)
                {
                    // num++;

                    if (excludes != null && excludes.Where(o => file.Contains(o)).Count() > 0)
                    {
                        Console.WriteLine("忽略:" + file);
                        continue;
                    }
                    //如果目标路径不存在,则创建目标路径
                    if (!System.IO.Directory.Exists(destFolder))
                    {
                        System.IO.Directory.CreateDirectory(destFolder);
                    }
                    string name = System.IO.Path.GetFileName(file);
                    string dest = System.IO.Path.Combine(destFolder, name);
                    System.IO.File.Copy(file, dest, true);//复制文件
                    Console.WriteLine($"from:{file} to:{dest}");
                }
                //得到原文件根目录下的所有文件夹
                string[] folders = System.IO.Directory.GetDirectories(sourceFolder);
                foreach (string folder in folders)
                {
                    string name = System.IO.Path.GetFileName(folder);
                    string dest = System.IO.Path.Combine(destFolder, name);
                    CopyFolder(folder, dest, excludes);//构建目标路径,递归复制文件
                }
                return true;
            } catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.ReadLine();
                return false;
            }
        }

        /// <summary>
        /// 用来遍历删除目录下的文件以及该文件夹
        /// </summary>
        public static bool DeleteFolder(this string path)
        {
            DirectoryInfo info = new DirectoryInfo(path);
            foreach (DirectoryInfo newInfo in info.GetDirectories())
            {
                DeleteFolder(newInfo.FullName);
            }
            foreach (FileInfo newInfo in info.GetFiles())
            {
                newInfo.Attributes = newInfo.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden);
                newInfo.Delete();
            }
            info.Attributes = info.Attributes & ~(FileAttributes.Archive | FileAttributes.ReadOnly | FileAttributes.Hidden);
            info.Delete();
            return true;
        }

        /// <summary>
        /// 重命名文件
        /// </summary>
        /// <param name="srcfilepath">源文件全路径（包括名字）</param>
        /// <param name="newFileName">新文件名字（不包括路径）</param>
        /// <returns></returns>
        public static bool RenameFile(this string srcfilepath, string newFileName)
        {
            if (!File.Exists(srcfilepath))
            {
                return false; ;
            }
            string filePath = Path.GetDirectoryName(srcfilepath);
            string newFilePath = Path.Combine(filePath, newFileName);
            System.IO.FileInfo file = new System.IO.FileInfo(srcfilepath);
            file.MoveTo(newFilePath);
            return true;
        }

        /// <summary>
        /// 格式化文件大小
        /// </summary>
        /// <param name="size"></param>
        /// <returns></returns>
        public static string FormatFileSize(this long size)
        {
            if (size >= 1024 * 1024 * 1024)
                return $"{(size / 1024.0 / 1024.0 / 1024.0).ToDouble(2)} GB";
            if (size >= 1024 * 1024)
                return $"{(size / 1024.0 / 1024.0).ToDouble(2)} MB";
            if (size >= 1024)
                return $"{(size / 1024.0).ToDouble(2)} KB";
            return $"{size} B";
        }

        /// <summary>
        /// 获取文件内容类型
        /// </summary>
        /// <param name="extension"></param>
        /// <returns></returns>
        public static string GetFileContentType(this string extension)
        {
            if (customMappings.ContainsKey(extension))
            {
                return customMappings[extension];
            }
            var provider = new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider();
            if (provider.Mappings.TryGetValue(extension, out string? contentType))
            {
                return contentType;
            }
            return "application/octet-stream";
        }

        public static string GetUrl(this IHttpContextAccessor httpContextAccessor, string path)
        {
            return $"{httpContextAccessor.HttpContext?.Request.Scheme}://{httpContextAccessor.HttpContext?.Request.Host.Value}/{path}";
        }

        public static string CombinePath(this string path1, string path2, string path3 = "", string path4 = "")
        {
            return Path.Combine(path1, path2, path3, path4);
        }

        public static string CombineAndFormatPath(this string path1, string path2, string path3 = "", string path4 = "")
        {
            return Path.Combine(path1, path2, path3, path4).FormatPath();
        }

        public static string CombineAndFormatPath(params string[] paths)
        {
            return Path.Combine(paths).FormatPath();
        }

        public static string FormatPath(this string path)
        {
            if (string.IsNullOrWhiteSpace(path))
                return string.Empty;

            return path.Replace(@"\", "/");
        }
    }
}